﻿using System;
using System.Data.Common;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Text.RegularExpressions;

using PublicDomain.Data.Csv.Properties;

namespace PublicDomain.Data.Csv
{
    public class CsvConnectionStringBuilder : DbConnectionStringBuilder
    {
        private const string databaseKey = "database";
        private const string delimiterKey = "delimiter";
        private const string headerRowsCountKey = "headerrowscount";
        private const string schemataFilePathKey = "schematafilepath";
        private const string parsingOptionsKey = "parsingoptions";

        public CsvConnectionStringBuilder(string connectionString)
            : base()
        {
            this.ConnectionString = connectionString;
        }

        public CsvConnectionStringBuilder()
            : this(null)
        {
        }

        public string Database
        {
            get
            {
                if (!this.ContainsKey(databaseKey))
                {
                    return null;
                }

                return (string)this[databaseKey];
            }

            set
            {
                this[databaseKey] = value;
            }
        }

        public char? Delimiter
        {
            get
            {
                if (!this.ContainsKey(delimiterKey))
                {
                    return null;
                }

                return Regex.Unescape((string)this[delimiterKey])[0];
            }

            set
            {
                this[delimiterKey] = value.ToString();
            }
        }

        [SuppressMessage("Microsoft.Design", "CA1065:DoNotRaiseExceptionsInUnexpectedLocations", Justification = "There is no virtual method for set connection string to intercept the change in connection string and perform the validation.")]
        public int? HeaderRowsCount
        {
            get
            {
                if (!this.ContainsKey(headerRowsCountKey))
                {
                    return default(int?);
                }

                var valueText = (string)this[headerRowsCountKey];
                if (String.IsNullOrWhiteSpace(valueText))
                {
                    return default(int?);
                }

                int value;
                if (!Int32.TryParse(valueText, NumberStyles.Integer | NumberStyles.AllowThousands, CultureInfo.InvariantCulture, out value))
                {
                    throw new CsvConnectionStringFormatException(String.Format(
                        CultureInfo.CurrentCulture,
                        Resources.HeaderRowsCountParsingError,
                        headerRowsCountKey,
                        valueText));
                }

                return value;
            }

            set
            {
                this[headerRowsCountKey] = value.ToString();
            }
        }

        public string SchemataFilePath
        {
            get
            {
                if (!this.ContainsKey(schemataFilePathKey))
                {
                    return null;
                }

                return (string)this[schemataFilePathKey];
            }

            set
            {
                this[schemataFilePathKey] = value;
            }
        }

        [SuppressMessage("Microsoft.Design", "CA1065:DoNotRaiseExceptionsInUnexpectedLocations", Justification = "There is no virtual method for set connection string to intercept the change in connection string and perform the validation.")]
        public CsvParsingOptions ParsingOptions
        {
            get
            {
                if (!this.ContainsKey(parsingOptionsKey))
                {
                    return CsvParsingOptions.None;
                }

                var valueText = (string)this[parsingOptionsKey];
                if (String.IsNullOrWhiteSpace(valueText))
                {
                    return CsvParsingOptions.None;
                }

                CsvParsingOptions value;
                if (!Enum.TryParse(valueText, true, out value))
                {
                    throw new CsvConnectionStringFormatException(String.Format(
                        CultureInfo.CurrentCulture,
                        Resources.ParsingOptionsParsingError,
                        headerRowsCountKey,
                        valueText,
                        typeof(CsvParsingOptions).EnumNamesToDelimitedText()));
                }

                return value;
            }

            set
            {
                this[parsingOptionsKey] = value.ToString();
            }
        }
    }
}
